1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.base.Preconditions.checkNotNull;
20  
21  import com.google.common.annotations.GwtCompatible;
22  
23  import java.util.EnumMap;
24  import java.util.Map;
25  
26  import javax.annotation.Nullable;
27  
28  /**
29   * A {@code BiMap} backed by an {@code EnumMap} instance for keys-to-values, and
30   * a {@code HashMap} instance for values-to-keys. Null keys are not permitted,
31   * but null values are. An {@code EnumHashBiMap} and its inverse are both
32   * serializable.
33   * 
34   * <p>See the Guava User Guide article on <a href=
35   * "http://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#BiMap">
36   * {@code BiMap}</a>.
37   *
38   * @author Mike Bostock
39   * @since 2.0 (imported from Google Collections Library)
40   */
41  @GwtCompatible(emulated = true)
42  public final class EnumHashBiMap<K extends Enum<K>, V>
43      extends AbstractBiMap<K, V> {
44    private transient Class<K> keyType;
45  
46    /**
47     * Returns a new, empty {@code EnumHashBiMap} using the specified key type.
48     *
49     * @param keyType the key type
50     */
51    public static <K extends Enum<K>, V> EnumHashBiMap<K, V>
52        create(Class<K> keyType) {
53      return new EnumHashBiMap<K, V>(keyType);
54    }
55  
56    /**
57     * Constructs a new bimap with the same mappings as the specified map. If the
58     * specified map is an {@code EnumHashBiMap} or an {@link EnumBiMap}, the new
59     * bimap has the same key type as the input bimap. Otherwise, the specified
60     * map must contain at least one mapping, in order to determine the key type.
61     *
62     * @param map the map whose mappings are to be placed in this map
63     * @throws IllegalArgumentException if map is not an {@code EnumBiMap} or an
64     *     {@code EnumHashBiMap} instance and contains no mappings
65     */
66    public static <K extends Enum<K>, V> EnumHashBiMap<K, V>
67        create(Map<K, ? extends V> map) {
68      EnumHashBiMap<K, V> bimap = create(EnumBiMap.inferKeyType(map));
69      bimap.putAll(map);
70      return bimap;
71    }
72  
73    private EnumHashBiMap(Class<K> keyType) {
74      super(WellBehavedMap.wrap(
75          new EnumMap<K, V>(keyType)),
76          Maps.<V, K>newHashMapWithExpectedSize(
77              keyType.getEnumConstants().length));
78      this.keyType = keyType;
79    }
80  
81    // Overriding these 3 methods to show that values may be null (but not keys)
82  
83    @Override
84    K checkKey(K key) {
85      return checkNotNull(key);
86    }
87  
88    @Override public V put(K key, @Nullable V value) {
89      return super.put(key, value);
90    }
91  
92    @Override public V forcePut(K key, @Nullable V value) {
93      return super.forcePut(key, value);
94    }
95  
96    /** Returns the associated key type. */
97    public Class<K> keyType() {
98      return keyType;
99    }
100 }
101